// sync.Cond 条件变量
package main

import (
	"log"
	"sync"
	"time"
)

func main() {
	var count uint8                          //消息数量,假设最多只能传递1条消息
	var lock sync.RWMutex                    //读写互斥锁
	sendCond := sync.NewCond(&lock)          //对共享资源写操作的条件变量,传入锁的指针
	recvCond := sync.NewCond(lock.RLocker()) //对共享资源读操作的条件变量,传入读锁

	sign := make(chan struct{}, 3) //用于传递演示完成的信号
	max := 5
	go func(max int) { // 发送消息
		defer func() {
			sign <- struct{}{}
		}()
		for i := 1; i <= max; i++ {
			time.Sleep(time.Millisecond * 500)
			lock.Lock() //先给互斥锁加锁
			for count == 1 {
				//循环检测是否复合预设条件, 需要重复执行 "检查状态 - 等待通知 - 被唤醒" 这个流程
				//解锁互斥锁,让当前goroutine处于阻塞状态
				//当通知到来的时候会唤醒这个goroutine并重新加锁,然后继续执行后续代码
				sendCond.Wait() //Wait方法会把当前的 goroutine 添加到通知队列的队尾
			}
			count = 1
			log.Printf("发送方%d: 消息已发送", i)
			lock.Unlock()
			recvCond.Signal() //从通知队列的队头开始查找可以被唤醒的 goroutine(一般是最早等待的那个)
		}
	}(max)
	go func(max int) { // 接收消息
		defer func() {
			sign <- struct{}{}
		}()
		for j := 1; j <= max; j++ {
			time.Sleep(time.Millisecond * 500)
			lock.RLock()
			for count == 0 { //循环检查如果消息数量为0,则等待通知
				recvCond.Wait()
			}
			//log.Printf("接收方%d: 消息为空", j)
			count = 0
			log.Printf("接收方%d: 已收到消息", j)
			lock.RUnlock()
			sendCond.Signal()
		}
	}(max)

	<-sign
	<-sign
}
